package com.baor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baor.dao.*;
import com.baor.domain.*;
import com.baor.domain.middle.Nouse;
import com.baor.domain.middle.RewardRuleMiddle;
import com.baor.enums.FuncEnum;
import com.baor.service.DistributorService;
import com.baor.utils.AjaxResult;
import com.baor.utils.DateUtil;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class DistributorServiceImpl implements DistributorService {

    @Autowired
    private DistributorDao distributorDao;
    @Autowired
    private VipDao vipDao;
    @Autowired
    private ProxyDao proxyDao;
    @Autowired
    private DistributionRecordDao distributionRecordDao;
    @Autowired
    private CycleDao cycleDao;
    @Autowired
    private RewardDao rewardDao;
    @Autowired
    private RewardRuleDao rewardRuleDao;
    @Autowired
    private RuleDao ruleDao;
    @Autowired
    private MoneyDao moneyDao;

    @Override
    public AjaxResult<?> selectList(Map<String, Object> param) {
        MPJLambdaWrapper<DistributorVo> mpj = new MPJLambdaWrapper<>();
        mpj.selectAll(DistributorVo.class)
                .selectAs(UserVo::getUserName, DistributorVo::getUserName)
                .selectAs(DistributionLevelVo::getLevelName,DistributorVo::getDistributorLevelName)
                .selectAs(UserVo::getUserDistributionMoney, DistributorVo::getTotalDistribution)
                .selectAs(UserVo::getUserTel, DistributorVo::getPhone)
                .selectFunc(FuncEnum.IF_STATUS, DistributorVo::getDistributiorStatus)
                .eq(DistributorVo::getSiteId, param.get("siteId"))
                .leftJoin(UserVo.class, UserVo::getUserId, DistributorVo::getUserId)
                .leftJoin(DistributionLevelVo.class, DistributionLevelVo::getDistributionLevelId, DistributorVo::getDistributionLevelId);
        if(param.get("info") != null && !"".equals(param.get("info"))){
            List<Integer> userId = getUserId(param);
            System.out.println(userId);
            if(userId.size() > 0)
                mpj.in(DistributorVo::getUserId, userId);
            else
                return AjaxResult.success(new ArrayList<>());
        }
        if(param.get("status") != null && !"".equals(param.get("status"))){
            mpj.eq(DistributorVo::getDistributiorStatus, param.get("status"));
        }
        if(param.get("startTime") != null && param.get("endTime") != null){
            mpj.gt(DistributorVo::getCreateTime, param.get("startTime"))
                   .lt(DistributorVo::getCreateTime, param.get("endTime"));
        }
        if(param.get("level") != null && !"".equals(param.get("level"))){
            mpj.eq(DistributorVo::getDistributionLevelId, param.get("level"));
        }
        if (param.get("distributorId") != null && !"".equals(param.get("distributorId"))){
            mpj.ne(DistributorVo::getDistributorId, param.get("distributorId"));
        }
        Map<String,Object> map = new HashMap<>();
        Page<DistributorVo> page = getPage(param);
        List<DistributorVo> list = distributorDao.selectPage(page, mpj).getRecords();
        for(DistributorVo vo : list){
            //计算已提现金额
            List<MoneyVo> moneyList = moneyDao.selectList(new LambdaQueryWrapper<MoneyVo>().eq(MoneyVo::getUserId, vo.getUserId()));
            List<MoneyVo> moneyList1 = moneyList.stream().filter(m -> m.getMoneyStatus().equals("1")).collect(Collectors.toList());
            BigDecimal totalMoney = new BigDecimal(0);
            for(MoneyVo money : moneyList1){
                totalMoney = totalMoney.add(money.getMoneyChange());
            }
            vo.setBackDistribution(totalMoney);
            vo.setSiteId(null);
            UserVo user = vipDao.selectById(vo.getUserId());
            int superiorId = Integer.parseInt(user.getUserSuperior());
            if(superiorId == 0){
                vo.setDistributiorSuperior("无");
            }else{
                UserVo superior = vipDao.selectById(superiorId);
                vo.setDistributiorSuperior(superior.getUserName());
            }
        }
        map.put("list", list);
        map.put("pageCount", page.getPages());
        return AjaxResult.success(map);
    }

    @Override
    public AjaxResult<?> freeze(Integer id) {
        DistributorVo vo = distributorDao.selectById(id);
        int row = 0;
        if(vo.getDistributiorStatus().equals("1")){
            vo.setDistributiorStatus("0");
            row = distributorDao.updateById(vo);
        }else{
            vo.setDistributiorStatus("1");
            row = distributorDao.updateById(vo);
        }
        if(row > 0)
            return AjaxResult.success();
        else
            return AjaxResult.error();
    }

    @Override
    public AjaxResult<?> updatelevel(DistributorVo vo) {
        int row = distributorDao.updateById(vo);
        if(row > 0)
            return AjaxResult.success();
        else
            return AjaxResult.error();
    }

    @Override
    @Transactional
    public AjaxResult<?> updateSuperior(DistributorVo vo) {
        int userId = Integer.parseInt(distributorDao.selectById(vo.getDistributorId()).getUserId());
        UserVo user = new UserVo();
        user.setUserId(userId);
        user.setUserSuperior(vo.getDistributiorSuperior());
        int row = vipDao.updateById(user);
        if(row > 0)
            return AjaxResult.success();
        else
            return AjaxResult.error();
    }

    @Override
    @Transactional
    public AjaxResult<?> insert(DistributorVo vo) {
        LambdaQueryWrapper<DistributorVo> lqw = new LambdaQueryWrapper<>();
        lqw.eq(DistributorVo::getUserId, vo.getUserId());
        List<DistributorVo> lists = distributorDao.selectList(lqw);
        if(lists.size() > 0){
            return AjaxResult.error("该用户已是分销商，请勿重复添加");
        }
        int userId = Integer.parseInt(distributorDao.selectById(vo.getDistributorId()).getUserId());
        UserVo user = new UserVo();
        user.setUserSuperior(userId+"");
        user.setUserId(Integer.valueOf(vo.getUserId()));
        vo.setDistributorId(null);
        vipDao.updateById(user);
        Boolean flag = true;
        while(flag){
            String code = "NO" + getNum();
            MPJLambdaWrapper<DistributorVo> mpj = new MPJLambdaWrapper<>();
            mpj.selectAll(DistributorVo.class)
                    .eq(DistributorVo::getDistributiorCode, code);
            List<DistributorVo> list = distributorDao.selectList(mpj);
            if(list.size() > 0){
                return AjaxResult.error("该编号已存在，请重新输入");
            }else {
                vo.setDistributiorCode(code);
                flag = false;
            }
        }
        vo.setCreateTime(DateUtil.now());
        int row = distributorDao.insert(vo);
        if (row > 0){
            return AjaxResult.success();
        }else {
            return AjaxResult.error();
        }
    }

    @Override
    public AjaxResult<?> details(Map<String, Object> param) {
        Map<String,Object> res = new HashMap<>();
        MPJLambdaWrapper<DistributorVo> mpj = new MPJLambdaWrapper<>();
        mpj.selectAll(DistributorVo.class)
                .selectAs(DistributionLevelVo::getLevelName,DistributorVo::getDistributorLevelName)
                .leftJoin(DistributionLevelVo.class, DistributionLevelVo::getDistributionLevelId, DistributorVo::getDistributionLevelId)
                .eq(DistributorVo::getDistributorId, param.get("distributorId"));
        DistributorVo vo = distributorDao.selectList(mpj).get(0);
        UserVo user = vipDao.selectById(vo.getUserId());
        //基础信息
        Map<String,Object> baseInfo = getBaseInfo(user,vo);
        //账户统计
        Map<String,Object> accountStat = getAccountStat(user,vo);
        //账户佣金记录
        res.put("moneyList", record(param).getData());

        res.put("baseInfo", baseInfo);
        res.put("accountStat", accountStat);
        return AjaxResult.success(res);
    }

    public Map<String,Object> getBaseInfo(UserVo user, DistributorVo vo){
        int superiorId = Integer.parseInt(user.getUserSuperior());
        if(superiorId == 0){
            vo.setDistributiorSuperior("无");
        }else{
            UserVo superior = vipDao.selectById(superiorId);
            vo.setDistributiorSuperior(superior.getUserName());
        }
        Map<String,Object> map = new HashMap<>();
        map.put("distributorCode", vo.getDistributiorCode());
        map.put("distributorLevelId", vo.getDistributionLevelId());
        map.put("distributorLevelName", vo.getDistributorLevelName());
        map.put("superior", vo.getDistributiorSuperior());
        map.put("userName", user.getUserName());
        map.put("iamge", user.getUserImage());
        map.put("tel", user.getUserTel());
        return map;
    }

    public Map<String,Object> getAccountStat(UserVo user, DistributorVo vo){
        Map<String,Object> map = new HashMap<>();
        map.put("canBe", user.getUserCanBe());
        map.put("totalDistribution", user.getUserTotalDistribution());
        //查看该分销商是否为代理商
        ProxyVo proxy = proxyDao.selectOne(new LambdaQueryWrapper<ProxyVo>().eq(ProxyVo::getUserId, user.getUserId()));
        if(proxy != null)
            map.put("proxyMoney", proxy.getProxyTotalMoney());
        else
            map.put("proxyMoney",new BigDecimal(0));
        //计算分销佣金
        List<DistributionRecordVo> list = distributionRecordDao.selectList(new LambdaQueryWrapper<DistributionRecordVo>().eq(DistributionRecordVo::getUserId, user.getUserId()));
        BigDecimal distributionMoney = new BigDecimal(0);
        for(DistributionRecordVo record : list){
            distributionMoney = distributionMoney.add(record.getPriceCost());
        }
        map.put("distributionMoney", distributionMoney);
        //计算销售奖励
        BigDecimal saleReward = getSaleReward(user.getUserId());
        map.put("saleReward", saleReward);
        return map;
    }

    public BigDecimal getSaleReward(Integer userId) {
        //查出索引周期
        List<CycleVo> cycleList = cycleDao.selectList(null);
        BigDecimal reward = new BigDecimal(0);
        all:for(CycleVo cycle : cycleList){
            //查看该周期是否开启奖励配置
            RewardVo rewardVo = rewardDao.selectOne(new LambdaQueryWrapper<RewardVo>().eq(RewardVo::getRewardConfId, cycle.getRewardConfId()));
            //奖励指标
            BigDecimal rewardLimit = rewardVo.getConfBasic();
            if(rewardVo.getConfStatus().equals("0")){
                continue;
            }
            //查出所有用户在该周期的奖励
            List<Nouse> list = rewardDao.sumReward(cycle);
            //过滤没有达到奖励指标的用户
            List<Nouse> filterList = list.stream().filter(nouse -> nouse.getGoodsValue().compareTo(rewardLimit) >= 0).collect(Collectors.toList());
            System.out.println(list.stream().map(Nouse::getUserId).collect(Collectors.toList()).contains(userId));
            if(list.stream().map(Nouse::getUserId).collect(Collectors.toList()).contains(userId)) {
                //查出该周期的奖励规则
                List<RuleVo> ruleList = getRule(Integer.parseInt(cycle.getRewardConfId()));
                for (int i = 1; i <= list.size(); i++) {
                    if (list.get(i-1).getUserId().equals(userId)) {
                        if(ruleList.get(ruleList.size()-1).getRuleRange() < i){
                            continue all;
                        }
                        reward = reward.add(getReward(ruleList, i));
                        break;
                    }
                }
            }
        }
        return reward;
    }

    public BigDecimal getReward(List<RuleVo> ruleList, int i) {
        BigDecimal reward = new BigDecimal(0);
        int count = 0;
        while(count < ruleList.size()){
            if(i <= ruleList.get(count).getRuleRange()){
                reward = reward.add(ruleList.get(count).getRuleMoney());
                break;
            }
            count++;
        }
        return reward;
    }

    public List<RuleVo> getRule(int rewardConfId){
        //查出该周期内所有奖励规则
        List<Integer> ruleIds = rewardRuleDao.selectList(new LambdaQueryWrapper<RewardRuleMiddle>()
                        .eq(RewardRuleMiddle::getRewardId, rewardConfId))
                .stream().map(RewardRuleMiddle::getRuleId).collect(Collectors.toList());
        List<RuleVo> list = ruleDao.selectList(new LambdaQueryWrapper<RuleVo>().in(RuleVo::getRuleId, ruleIds).orderByDesc(RuleVo::getRuleMoney));
        return list;
    }



    @Override
    public AjaxResult<?> teamInfo(Map<String, Object> param) {
        int id = Integer.parseInt(param.get("distributorId").toString());
        List<Map<String,Object>> list = new ArrayList<>();
        int userId = Integer.parseInt(distributorDao.selectById(id).getUserId());
        LambdaQueryWrapper<UserVo> lqw = new LambdaQueryWrapper<>();
        lqw.eq(UserVo::getUserSuperior, userId);
        Page<UserVo> page = getPage2(param);
        List<UserVo> vos = vipDao.selectPage(page, lqw).getRecords();
        for(UserVo vo : vos){
            Map<String,Object> map = new HashMap<>();
            map.put("userName", vo.getUserName());
            if(distributorDao.selectOne(new LambdaQueryWrapper<DistributorVo>().eq(DistributorVo::getUserId, vo.getUserId())) == null){
                map.put("isDistributor", "否");
            }else{
                map.put("isDistributor", "是");
            }
            map.put("createTime", vo.getCreateTime());
            list.add(map);
        }
        Map<String,Object> res = new HashMap<>();
        res.put("list", list);
        res.put("pageCount", page.getPages());
        return AjaxResult.success(res);
    }

    @Override
    public AjaxResult<?> record(Map<String, Object> param) {
        Integer userId = Integer.valueOf(distributorDao.selectOne(new LambdaQueryWrapper<DistributorVo>()
                .eq(DistributorVo::getDistributorId, param.get("distributorId"))).getUserId());
        Page<MoneyVo> page = getPage3(param);
        LambdaQueryWrapper<MoneyVo> lqw = new LambdaQueryWrapper<>();
        lqw.select(MoneyVo::getMoneyChange,MoneyVo::getMoneySourceId,MoneyVo::getMoneyFinal,MoneyVo::getCreateTime)
                .eq(MoneyVo::getUserId, userId);
        List<MoneyVo> list = moneyDao.selectPage(page, lqw).getRecords();
        Map<String,Object> res = new HashMap<>();
        res.put("list", list);
        res.put("pageCount", page.getPages());
        return AjaxResult.success(res);
    }

    @Override
    public AjaxResult<?> chooseVip(Map<String, Object> param) {
        Page<UserVo> page = getPage2(param);
        List<Integer> distributorIds = distributorDao.selectList(null).stream().map(DistributorVo::getUserId).map(Integer::parseInt).collect(Collectors.toList());
        MPJLambdaWrapper<UserVo> lqw = new MPJLambdaWrapper<UserVo>();
        lqw.select(UserVo::getUserId,UserVo::getUserName,UserVo::getUserTel)
                .notIn(UserVo::getUserId, distributorIds)
                .eq(UserVo::getSiteId, param.get("siteId"));
        if(param.get("phone") != null && !"".equals(param.get("phone")))
            lqw.like(UserVo::getUserTel, param.get("phone"));
        List<UserVo> vos = vipDao.selectPage(page, lqw).getRecords();
        Map<String,Object> res = new HashMap<>();
        res.put("list", vos);
        res.put("pageCount", page.getPages());
        return AjaxResult.success(vos);
    }

    @Override
    public AjaxResult<?> chooseDistributor(Map<String, Object> param) {
        Page<DistributorVo> page = getPage(param);
        MPJLambdaWrapper<DistributorVo> lqw = new MPJLambdaWrapper<>();
        lqw.select(DistributorVo::getDistributorId,DistributorVo::getUserId,DistributorVo::getDistributionLevelId)
                .selectAs(UserVo::getUserName,DistributorVo::getUserName)
                .selectAs(UserVo::getUserTel,DistributorVo::getPhone)
                .selectAs(DistributionLevelVo::getLevelName,DistributorVo::getDistributorLevelName)
                .selectFunc(FuncEnum.IF_STATUS, DistributorVo::getDistributiorStatus)
                .leftJoin(UserVo.class, UserVo::getUserId, DistributorVo::getUserId)
                .leftJoin(DistributionLevelVo.class, DistributionLevelVo::getDistributionLevelId, DistributorVo::getDistributionLevelId)
                .eq(DistributorVo::getDistributiorStatus, "1")
                .eq(DistributorVo::getSiteId, param.get("siteId"));
        if(param.get("info") != null && !"".equals(param.get("info")))
            lqw.like(UserVo::getUserTel, param.get("info"))
                    .or(x -> x.like(UserVo::getUserName, param.get("info")));
        Map<String,Object> res = new HashMap<>();
        res.put("list", distributorDao.selectPage(page, lqw).getRecords());
        res.put("pageCount", page.getPages());
        return AjaxResult.success(res);
    }

    public static int getNum(){
        int min = 100000;
        int max = 999999;
        int num = (int)(Math.random() * ((max - min) + 1)) + min;
        return num;
    }


    public List<Integer> getUserId(Map<String, Object> param) {
        MPJLambdaWrapper<UserVo> mpj = new MPJLambdaWrapper<>();
        mpj.select(UserVo::getUserId)
               .like(UserVo::getUserName, param.get("info").toString());
        return vipDao.selectList(mpj).stream().map(UserVo::getUserId).collect(Collectors.toList());
    }

    private Page<DistributorVo> getPage(Map<String,Object> map){
        if ( map.get("pageIndex") == null || "".equals(map.get("pageIndex")) )
            map.put("pageIndex",1);
        if ( map.get("pageSize") == null || "".equals(map.get("pageSize")) )
            map.put("pageSize",10);
        Long pageIndex = Long.valueOf(map.get("pageIndex").toString());
        Long pageSize = Long.valueOf(map.get("pageSize").toString());
        Page<DistributorVo> page = new Page<>(pageIndex,pageSize);
        return page;
    }

    private Page<UserVo> getPage2(Map<String,Object> map){
        if ( map.get("pageIndex") == null || "".equals(map.get("pageIndex")) )
            map.put("pageIndex",1);
        if ( map.get("pageSize") == null || "".equals(map.get("pageSize")) )
            map.put("pageSize",10);
        Long pageIndex = Long.valueOf(map.get("pageIndex").toString());
        Long pageSize = Long.valueOf(map.get("pageSize").toString());
        Page<UserVo> page = new Page<>(pageIndex,pageSize);
        return page;
    }

    private Page<MoneyVo> getPage3(Map<String,Object> map){
        if ( map.get("pageIndex") == null || "".equals(map.get("pageIndex")) )
            map.put("pageIndex",1);
        if ( map.get("pageSize") == null || "".equals(map.get("pageSize")) )
            map.put("pageSize",10);
        Long pageIndex = Long.valueOf(map.get("pageIndex").toString());
        Long pageSize = Long.valueOf(map.get("pageSize").toString());
        Page<MoneyVo> page = new Page<>(pageIndex,pageSize);
        return page;
    }



}
